#pragma once

#include "Socket.hpp"
#include "TcpServer.hpp"
#include "Util.hpp"
#include "Log.hpp"
#include <memory>
#include <iostream>
#include <string>
#include <unordered_map>
#include <sstream>
#include <functional>

using namespace SocketMoudle;
using namespace LogMoudle;

const std::string gspace = " ";        // 空格
const std::string glinespace = "\r\n"; // 换行符
const std::string glinesep = ": ";     // 行分隔符

const std::string webroot = "./wwwroot";   // Web根目录(指定目录)，所有资源都放在该目录下
const std::string homepage = "index.html"; // 首页
const std::string page_404 = "/404.html";

// HTTP请求协议(结构化数据)
class HttpRequest
{
public:
    HttpRequest() : _is_interact(false)
    {
    }
    // 序列化
    std::string Serialize()
    {
        return std::string();
    }

    void ParseReqLine(std::string &reqline)
    {
        // 字符串分割
        std::stringstream ss(reqline);
        // stringstream流里的数据以空格为单位写到_method,_uri,_version里
        ss >> _method >> _uri >> _version;
    }

    // 反序列化
    bool Deserialize(std::string &reqstr) // 请求字符串
    {
        // 1. 提取请求中的请求行
        std::string reqline;
        bool res = Util::ReadOneLine(reqstr, &reqline, glinespace);
        LOG(LogLevel::DEBUG) << reqline;

        std::cout << "\n";

        // 2. 请求行反序列化
        ParseReqLine(reqline);

        if (_uri == "/")
            _uri = webroot + _uri + homepage; // 默认访问的是首页：./wwwroot/index.html
        else
            _uri = webroot + _uri; // 指定路径下的文件：./wwwroot/a/b/c.html

        LOG(LogLevel::DEBUG) << "_method: " << _method;
        LOG(LogLevel::DEBUG) << "_uri: " << _uri;
        LOG(LogLevel::DEBUG) << "_version: " << _version;

        const std::string temp = "?";
        auto pos = _uri.find(temp);
        if (pos == std::string::npos) // 不存在交互
        {
            return true;
        }
        // ./wwwroot/Login.html?username=zhangsan&password=111
        _args = _uri.substr(pos + temp.size());
        _uri = _uri.substr(0, pos); // ?前半部分才是URI, 提取出来
        _is_interact = true;
        return true;
    }

    std::string Uri() { return _uri; }
    bool IsInteract() { return _is_interact; }
    std::string Args() { return _args; }
    ~HttpRequest()
    {
    }

private:
    std::string _method;
    std::string _uri;
    std::string _version; // 版本

    std::unordered_map<std::string, std::string> _header; // 请求报头
    std::string _blank;                                   // 空行
    std::string _text;                                    // 正文

    std::string _args; // 用户传上来的参数
    bool _is_interact; // 是否交互
};

// HTTP应答协议(结构化数据)
class HttpResponse
{
public:
    HttpResponse() : _backline(glinespace), _version("HTTP/1.0")
    {
    }

    // 序列化：成熟的http的应答序列化，不依赖任何第三方库
    std::string Serialize()
    {
        // 状态行
        std::string statue_line = _version + gspace + std::to_string(_code) + gspace + _desc + glinespace;
        // 响应报头
        std::string resp_header;
        // 拼接响应报头
        for (auto &header : _headers)
        {
            std::string line = header.first + glinesep + header.second + glinespace;
            resp_header += line;
        }

        return statue_line + resp_header + _backline + _text;
    }

    // 反序列化
    bool Deserialize(std::string &reqstr) // 请求字符串
    {
        return true;
    }
    // 设置目标文件
    void SetTargetFile(const std::string &target)
    {
        _targetfile = target;
    }

    // 设置状态码
    void SetCode(int code)
    {
        _code = code;
        switch (_code)
        {
        case 200:
            _desc = "OK";
            break;
        case 404:
            _desc = "Not Found";
            break;
        case 301:
            _desc = "Move Permanently"; // 永久重定向
            break;
        case 302:
            _desc = "See Other";
            break;
        default:
            break;
        }
    }

    // 设置响应报头
    void SetHeader(const std::string &key, const std::string &value)
    {
        auto iter = _headers.find(key);
        if (iter != _headers.end()) // 存在就不插入
            return;

        _headers.insert(std::make_pair(key, value));
    }

    // 文件资源转化成后缀格式
    std::string Uri2Suffix(const std::string &targetfile)
    {
        // ./wwwroot/a/c/c.html
        auto pos = targetfile.rfind("."); // 从后往前找
        if (pos == std::string::npos)
        {
            return "text/html";
        }
        std::string suffix = targetfile.substr(pos);
        if (suffix == ".html" || suffix == ".htm")
            return "text/html";
        else if (suffix == ".jpg")
            return "image/jpg";
        else if (suffix == ".png")
            return "image/png";
        else
            return "";
    }

    // 制作应答
    bool MakeResponse()
    {
        if (_targetfile == "./wwwroot/favicon.ico")
        {
            LOG(LogLevel::DEBUG) << "用户请求：" << _targetfile << "忽略它";
            return false;
        }
        if (_targetfile == "./wwwroot/redir_test")
        { // 设置临时重定向
            SetCode(302);
            SetHeader("Location", "https://blog.csdn.net/2401_83431652?type=blog");
            return true;
        }

        int filesize = 0;
        bool res = Util::ReadFileContent(_targetfile, &_text);
        if (!res)
        {
            LOG(LogLevel::WARNING) << "client want get : " << _targetfile << " , but not found";
            SetCode(404);
            _targetfile = webroot + page_404;
            filesize = Util::FileSize(_targetfile);
            Util::ReadFileContent(_targetfile, &_text);
            std::string suffix = Uri2Suffix(_targetfile); // 文件资源转化成后缀格式
            SetHeader("Content-type", suffix);
            SetHeader("Content-Length", std::to_string(filesize)); // 设置属性

            // // 读取错误时，可以直接重定向到404页面
            // SetCode(302);
            // SetHeader("Location", "http://43.138.121.254:8080/404.html");
            // return true;
        }
        else
        {
            LOG(LogLevel::DEBUG) << "读取文件：" << _targetfile;
            SetCode(200);
            filesize = Util::FileSize(_targetfile);       // 获取目标文件大小
            std::string suffix = Uri2Suffix(_targetfile); // 文件资源转化成后缀格式
            SetHeader("Content-type", suffix);
            SetHeader("Content-Length", std::to_string(filesize)); // 设置属性
        }

        return true;
    }

    void SetText(const std::string &t)
    {
        _text = t;
    }

    ~HttpResponse()
    {
    }
    // private:
public:
    std::string _version;                                  // 版本
    int _code;                                             // 状态码
    std::string _desc;                                     // 状态码描述
    std::unordered_map<std::string, std::string> _headers; // 响应报头
    std::string _backline;                                 // 空行
    std::string _text;                                     // 正文

    std::string _targetfile;
};

using http_funt_t = std::function<void(HttpRequest &req, HttpResponse &resp)>;

// 1. 返回静态资源
// 2. 提供动态交互的能力
class Http
{
public:
    Http(uint16_t port) : tsvrp(std::make_unique<TcpServer>(port))
    {
    }
    // 调用http的请求处理
    void HandlerHttpRequest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        // 收到请求
        std::string httpreqstr;
        // 假设读到了完整的请求(bug)
        int n = sock->Recv(&httpreqstr); // 接收到浏览器发来的http请求字符串，Tcp是面向字节流的 -> recv是有问题的
        if (n > 0)
        {
            // 审核报文完整性...(缺)
            HttpRequest req;
            HttpResponse resp;
            req.Deserialize(httpreqstr);
            if (req.IsInteract()) // 是否要交互
            {
                // _uri: ./wwwroot/login
                if (_route.find(req.Uri()) == _route.end())
                { // 该方法不存在, 返回404页面
                    // resp.SetCode(302);
                    resp.SetCode(404);
                    resp.SetTargetFile(webroot + page_404);
                    resp.MakeResponse();
                    sock->Send(resp.Serialize());
                }
                else
                { // 执行回调
                    _route[req.Uri()](req, resp);
                    // 不用制作静态的应答
                    std::string response_str = resp.Serialize(); // 序列化
                    sock->Send(response_str);                    // 把应答发出去
                }
            }
            else // 不用交互，静态应答
            {
                resp.SetTargetFile(req.Uri());
                if (resp.MakeResponse())
                {
                    std::string response_str = resp.Serialize(); // 序列化
                    sock->Send(response_str);                    // 把应答发出去
                }
            }

            // std::string filename = req.Uri(); // 拿到请求的资源
            // 构建应答
            // HttpResponse resp;
            // resp._version = "HTTP/1.1";
            // resp._code = 200; // 成功
            // resp._desc = "OK";
            // LOG(LogLevel::DEBUG) << "用户请求：" << filename;
            // bool res = Util::ReadFileContent(filename, &(resp._text)); // 读取的网页是以文件的形式存在的, 拿到的请求写到正文里面
            // (void)res;
        }

// #ifndef DEBUG
// #define DEBUG
#ifdef DEBUG
        // // 收到请求
        // std::string httpreqstr;
        // // 假设读到了完整的请求
        // sock->Recv(&httpreqstr); // 接收到浏览器发来的http请求字符串，Tcp是面向字节流的 -> recv是有问题的
        // std::cout << httpreqstr;

        // // 直接构建应答：内存级别+固定
        // // htpp短连接，对客户端提供短服务
        // HttpResponse resp;
        // resp._version = "HTTP/1.1";
        // resp._code = 200; // 成功
        // resp._desc = "OK";

        // std::string filename = webroot + homepage;                 // "./wwwroot/index.html"
        // bool res = Util::ReadFileContent(filename, &(resp._text)); // 读取的网页是以文件的形式存在的
        // (void)res;

        // std::string response_str = resp.Serialize(); // 序列化
        // sock->Send(response_str);                    // 把应答发出去
#endif
        // 对请求字符串进行反序列化
    }
    void Start()
    {
        tsvrp->Start([this](std::shared_ptr<Socket> &sock, InetAddr &client)
                     { this->HandlerHttpRequest(sock, client); });
    }

    // 注册登录服务
    void RegisterService(const std::string name, http_funt_t h)
    {
        std::string key = webroot + name;

        auto iter = _route.find(key);
        if (iter == _route.end())
        {
            _route.insert(std::make_pair(key, h));
        }
    }

    ~Http()
    {
    }

private:
    std::unique_ptr<TcpServer> tsvrp;
    std::unordered_map<std::string, http_funt_t> _route; // 路由
};